package com.wjk.kylin.core.exception;

import cn.hutool.http.HttpStatus;
import com.wjk.kylin.core.common.data.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wangjkui
 * @description 全局的的异常拦截器（拦截所有的控制器）（带有@RequestMapping注解的方法上都会拦截）
 * @date 2020/5/22
 */
@Slf4j
@Order(-1)
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 拦截未知的异常
     */
    @ExceptionHandler(Exception.class)
    public ResponseData handleException(Exception e) {
        log.error("服务器未知异常:{}", e.getMessage(), e);
        return ResponseData.error(e.getMessage());
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseData handleRuntimeException(RuntimeException e) {
        log.error("服务器未知运行时异常:{}", e.getMessage(), e);
        return ResponseData.error(e.getMessage());
    }

    /**
     * 拦截业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseData handleBusinessException(BusinessException e) {
        log.error("业务异常 msg:{},code:{}", e.getMessage(), e.getCode());
        return ResponseData.error(e.getCode(), e.getMessage());
    }

    /**
     * 请求异常
     */
    @ExceptionHandler(RequestException.class)
    public ResponseData handleRequestException(RequestException e) {
        log.error("请求异常 msg:{},code:{}", e.getMessage(), e.getCode());
        return ResponseData.error(e.getCode(), e.getMessage());
    }

    /**
     * Handle business exception map.
     * 用户名错误
     *
     * @param e the ex
     * @return the map
     */
    @ExceptionHandler(UsernameNotFoundException.class)
    public ResponseData handleUsernameNotFoundException(UsernameNotFoundException e) {
        log.error("用户名错误:{}", e.getMessage());
        return ResponseData.error(HttpStatus.HTTP_BAD_REQUEST, "用户名或密码错误");
    }

    /**
     * Handle business exception map.
     * 用户名或密码错误
     *
     * @param e the ex
     * @return the map
     */
    @ExceptionHandler(BadCredentialsException.class)
    public ResponseData handleBadCredentialsException(BadCredentialsException e) {
        log.error("用户名或密码错误:{}", e.getMessage());
        return ResponseData.error(HttpStatus.HTTP_BAD_REQUEST, "用户名或密码错误");
    }

    /**
     * Handle constraint violation exception map.
     * 缺少请求参数的验证 RequestParam required = true 是没有传必要的参数
     *
     * @param e the e
     * @return the map
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseData handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("缺少请求参数的验证:{}", e.getMessage());
        return ResponseData.error(HttpStatus.HTTP_BAD_REQUEST, "请求参数验证错误");
    }

    /**
     * Handle constraint violation exception map.
     * 请求为分开的验证参数
     *
     * @param e the e
     * @return the map
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseData handleConstraintViolationException(ConstraintViolationException e) {
        log.error("请求为分开的验证参数:{}", e.getMessage());
        List<String> message = e.getConstraintViolations().stream().limit(1).map(ConstraintViolation::getMessage).collect(Collectors.toList());
        log.error("请求为分开的验证参数:{}", message.get(0));
        return ResponseData.error(HttpStatus.HTTP_BAD_REQUEST, message.get(0));
    }

    /**
     * 请求封为对象的验证参数
     *
     * @param e the e
     * @return the map
     */
    @ExceptionHandler(BindException.class)
    public ResponseData handleBindException(BindException e) {
        log.error("请求封为对象的验证参数:{}", e.getMessage());
        String message = e.getAllErrors().get(0).getDefaultMessage();
        log.error("请求封为对象的验证参数:{}", message);
        return ResponseData.error(HttpStatus.HTTP_BAD_REQUEST, message);
    }

    /**
     * 请求封为对象的验证参数
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseData handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("请求封为对象的验证参数:{}", e.getMessage());
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        log.error("请求封为对象的验证参数:{}", message);
        return ResponseData.error(HttpStatus.HTTP_BAD_REQUEST, message);
    }

}
